﻿using Microsoft.EntityFrameworkCore.Storage;
using MySqlConnector;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Auditing;
using Volo.Abp;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.Users;
using Volo.Abp.Timing;
using Volo.Abp.Domain.Entities;
using Volo.Abp.EntityFrameworkCore;

namespace Bridge.Shared.Extensions
{
    /// <summary>
    /// 批量更新接口
    /// </summary>
    [ExposeServices(typeof(IEfCoreBulkOperationProvider))]
    public class EfCoreBulkOperationProvider : IEfCoreBulkOperationProvider, ITransientDependency
    {
        protected ICurrentUser CurrentUser { get; }
        protected IClock Clock { get; }
        public EfCoreBulkOperationProvider(ICurrentUser currentUser, IClock clock) {
            CurrentUser = currentUser;
            Clock = clock;
        }

       public async Task InsertManyAsync<TDbContext, TEntity>(
            IEfCoreRepository<TEntity> repository,
            IEnumerable<TEntity> entities,
            bool autoSave,
            CancellationToken cancellationToken)
            where TDbContext : IEfCoreDbContext
            where TEntity : class, IEntity
        {
            var context = await repository.GetDbContextAsync();
            var tran = context.Database.CurrentTransaction?.GetDbTransaction();
            List<TEntity> entityList = entities.ToList();
            foreach (var item in entityList)
            {
                ObjectHelper.TrySetProperty(item.As<IHasCreationTime>(), x => x.CreationTime, () => Clock.Now);
                ObjectHelper.TrySetProperty(item.As<IMayHaveCreator>(), x => x.CreatorId, () => CurrentUser.Id);
            }
            CancellationTokenSource cts = new CancellationTokenSource();
            cts.CancelAfter(360000000);
            await context.BulkInsertAsync(entityList, tran as MySqlTransaction, cts.Token, 0);
            if (autoSave)
            {
                await context.SaveChangesAsync(cancellationToken: cancellationToken);
            }
        }

        public async Task UpdateManyAsync<TDbContext, TEntity>(
            IEfCoreRepository<TEntity> repository,
            IEnumerable<TEntity> entities,
            bool autoSave,
            CancellationToken cancellationToken)
            where TDbContext : IEfCoreDbContext
            where TEntity : class, IEntity
        {
            var context = await repository.GetDbContextAsync();

            List<TEntity> entityList = entities.ToList();

            context.Set<TEntity>().UpdateRange(entityList);


            if (autoSave)
            {
                await context.SaveChangesAsync(cancellationToken: cancellationToken);
            }
        }

        public async Task DeleteManyAsync<TDbContext, TEntity>(
            IEfCoreRepository<TEntity> repository,
            IEnumerable<TEntity> entities,
            bool autoSave,
            CancellationToken cancellationToken)
            where TDbContext : IEfCoreDbContext
            where TEntity : class, IEntity
        {
            var context = await repository.GetDbContextAsync();

            List<TEntity> entityList = entities.ToList();

            context.RemoveRange(entityList);

            if (autoSave)
            {
                await context.SaveChangesAsync(cancellationToken: cancellationToken);
            }


        }
    }
}
